package com.kinghood.productcenter.service.product.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinghood.infrastructure.api.authority.SysLogModuleEnum;
import com.kinghood.infrastructure.api.authority.UserRemoteVo;
import com.kinghood.infrastructure.aspect.OperatorLog;
import com.kinghood.infrastructure.model.KingHoodExceptionUtil;
import com.kinghood.infrastructure.model.KingHoodResponseVO;
import com.kinghood.infrastructure.model.constant.CommonConstants;
import com.kinghood.infrastructure.model.dto.StatusRemarkReqDTO;
import com.kinghood.infrastructure.model.enums.StatusEnum;
import com.kinghood.infrastructure.util.UserUtil;
import com.kinghood.infrastructure.util.base.IdGenUtil;
import com.kinghood.productcenter.common.api.authority.UserRemote;
import com.kinghood.productcenter.common.model.constants.ProductConstant;
import com.kinghood.productcenter.common.model.dao.product.*;
import com.kinghood.productcenter.common.model.dto.base.AttributeCodesReqDTO;
import com.kinghood.productcenter.common.model.dto.base.AttributeReqDTO;
import com.kinghood.productcenter.common.model.dto.base.SkuQueryPageReqDTO;
import com.kinghood.productcenter.common.model.dto.product.*;
import com.kinghood.productcenter.common.model.dto.sku.GetProductSkuReqDTO;
import com.kinghood.productcenter.common.model.dto.sku.ProductSkuReqDTO;
import com.kinghood.productcenter.common.model.dto.sku.SkuDTO;
import com.kinghood.productcenter.common.model.dto.sku.UpdateProductSkuReqDTO;
import com.kinghood.productcenter.common.model.enums.product.BusinessLogOperateEnum;
import com.kinghood.productcenter.common.model.enums.product.ProductStatusEnums;
import com.kinghood.productcenter.common.model.vo.base.AttributeNameVO;
import com.kinghood.productcenter.common.model.vo.base.BaseAttributeVO;
import com.kinghood.productcenter.common.model.vo.product.*;
import com.kinghood.productcenter.common.utils.UserNameUtil;
import com.kinghood.productcenter.dao.product.ProductBaseMapper;
import com.kinghood.productcenter.dao.product.ProductSkuBaseMapper;
import com.kinghood.productcenter.service.async.IAsyncBusinessLogService;
import com.kinghood.productcenter.service.base.IBaseAttributeService;
import com.kinghood.productcenter.service.product.*;
import com.kinghood.productcenter.service.product.handler.ProductBaseHandler;
import com.kinghood.sharding.model.KingHoodPageUtil;
import com.kinghood.sharding.model.KingPageResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author KingHood
 * @since 2023-12-20
 */
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
@Slf4j
@Service
public class ProductSkuBaseServiceImpl extends ServiceImpl<ProductSkuBaseMapper, ProductSkuBaseDO> implements IProductSkuBaseService {

    private final ProductBaseMapper productBaseMapper;
    private final IProductAttributeService productAttributeService;
    private final IProductSkuExtrasBaseService productSkuExtrasBaseService;
    private final IProductSkuSupplierBaseService productSkuSupplierBaseService;
    private final UserRemote userRemote;
    private final IUserSearchSettingService userSearchSettingService;
    private final IBaseAttributeService baseAttributeService;
    private final IAsyncBusinessLogService asyncBusinessLogService;


    @Override
    public List<ProductSkuBaseDO> addSku(List<ProductSkuReqDTO> skuInList, Long productId, Map<String, BaseAttributeVO> attributeVOMap, Map<String, Long> skuCodeMap) {

        if (CollectionUtils.isEmpty(skuInList)) {
            return Collections.emptyList();
        }

        List<ProductSkuBaseDO> skuList = new ArrayList<>();
        List<ProductAttributeDO> attributeList = new ArrayList<>();

        // 检查skuCode是否重复
        List<String> skuCodeList = skuInList.stream().map(ProductSkuReqDTO::getSkuCode).collect(Collectors.toList());
        List<Long> skuIdList = skuInList.stream().map(ProductSkuReqDTO::getSkuId).collect(Collectors.toList());
        HashSet<String> skuCodeSet = new HashSet<>(skuCodeList);
        KingHoodExceptionUtil.trueThrows(skuCodeSet.size() < skuCodeList.size(), "sku编码不可重复");

        Long count = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(ProductSkuBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .in(ProductSkuBaseDO::getSkuCode, skuCodeList)
                .notIn(ProductSkuBaseDO::getId, skuIdList)
                .count();
        KingHoodExceptionUtil.trueThrows(count > 0, "sku编码已存在");

        skuInList.forEach(sku -> {
            ProductSkuBaseDO skuBase = new ProductSkuBaseDO();
            Long id = skuCodeMap.get(sku.getSkuCode());
            if (Objects.isNull(id)) {
                id = IdGenUtil.getId();
            }
            skuBase.setId(id);
            skuBase.setProductId(productId);
            skuBase.setSkuUuid(sku.getSkuUuid());
            skuBase.setSkuCode(sku.getSkuCode());
            skuBase.setSkuStatus(sku.getSkuStatus());
            skuBase.setCreateTime(LocalDateTime.now());
            skuBase.setUpdateTime(LocalDateTime.now());
            skuBase.setCreateUserId(UserUtil.getUserId());
            skuList.add(skuBase);

            if (CollectionUtils.isEmpty(sku.getAttributes())) {
                return;
            }
            sku.getAttributes().forEach((k, y) -> {
                if (ProductConstant.NO_ATTRIBUTE_LIST.contains(k)) {
                    return;
                }
                BaseAttributeVO baseAttributeVO = attributeVOMap.get(k);
                KingHoodExceptionUtil.isNull(baseAttributeVO, "属性" + k + "不存在");

                ProductAttributeDO productAttributeDO = new ProductAttributeDO();
                productAttributeDO.setId(IdGenUtil.getId());
                productAttributeDO.setProductId(productId);
                productAttributeDO.setBusinessId(skuBase.getId());
                productAttributeDO.setBusinessType(ProductAttributeDO.BUSINESS_TYPE_SKU);
                productAttributeDO.setAttributeId(baseAttributeVO.getId());
                productAttributeDO.setAttributeCode(baseAttributeVO.getAttributeCode());
                productAttributeDO.setValue(ProductBaseHandler.handleAttributeValue(y));
                productAttributeDO.setValueFind(ProductBaseHandler.handleAttributeValueFind(productAttributeDO.getValue()));
                productAttributeDO.setValueType(baseAttributeVO.getValueType());
                productAttributeDO.setCreateTime(LocalDateTime.now());
                productAttributeDO.setCreateTime(LocalDateTime.now());
                productAttributeDO.setCreateUserId(UserUtil.getUserId());
                attributeList.add(productAttributeDO);
            });
        });

        this.saveBatch(skuList);
        productAttributeService.saveBatch(attributeList);


        return skuList;
    }

    @Override
    public void deleteByProductId(Long id) {

        new LambdaUpdateChainWrapper<>(this.getBaseMapper())
                .eq(ProductSkuBaseDO::getProductId, id)
                .eq(ProductSkuBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .remove();
    }

    @Override
    public Map<String, Long> getSkuByProductId(Long id) {

        List<ProductSkuBaseDO> list = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(ProductSkuBaseDO::getProductId, id)
                .eq(ProductSkuBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .list();

        Map<String, Long> skuCodeMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(list)) {
            skuCodeMap = list.stream()
                    .collect(Collectors.toMap(ProductSkuBaseDO::getSkuCode, ProductSkuBaseDO::getId, (k1, k2) -> k1));
        }
        return skuCodeMap;
    }

    @Override
    public List<String> getSkuCodeList(Long productId) {
        return this.getBaseMapper().getSkuCodeList(productId);
    }

    /**
     * 查询页面
     *
     * @param in 在里面
     * @return @return {@link Object }
     * @author jp
     * @date 2024/01/23 15:22
     */
    @Override
    public Object queryPage(SkuQueryPageReqDTO in) {
        Page<ProductSkuListVO> result = listSku(in);
        if (com.alibaba.nacos.common.utils.CollectionUtils.isNotEmpty(in.getShowAttributeList()) && !result.getRecords().isEmpty()) {
            JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(result.getRecords()));
            List<JSONObject> arrResult = new ArrayList<>();
            List<Long> skuList = result.getRecords().stream().map(ProductSkuListVO::getId).collect(Collectors.toList());
            // 查询出属性
            Map<Long, List<ProductAttributeListVO>> attributeListVOMap =
                    productAttributeService.getSkuAttributeByCode(in.getShowAttributeList(), skuList);
            for (int i = 0; i < jsonArray.size(); i++) {
                List<String> mustShow = new ArrayList<>();
                mustShow.addAll(in.getShowAttributeList());
                // 把属性放入对象中
                List<ProductAttributeListVO> attributeListVOS = attributeListVOMap.get(jsonArray.getJSONObject(i).getLong("id"));
                if (com.alibaba.nacos.common.utils.CollectionUtils.isNotEmpty(attributeListVOS)) {
                    for (ProductAttributeListVO attribute : attributeListVOS) {
                        jsonArray.getJSONObject(i).put(attribute.getCode(), attribute.getValue());
                        mustShow.remove(attribute.getCode());
                    }
                }
                if (!CollectionUtils.isEmpty(mustShow)) {
                    for (String fields : mustShow) {
                        jsonArray.getJSONObject(i).put(fields, null);
                    }
                }
                arrResult.add(jsonArray.getJSONObject(i));
            }
            Page<JSONObject> arrayPage = new Page<>();
            arrayPage.setCurrent(result.getCurrent());
            arrayPage.setPages(result.getPages());
            arrayPage.setTotal(result.getTotal());
            arrayPage.setRecords(arrResult);
            return KingPageResult.getResult(arrayPage);
        }
        return KingPageResult.getResult(result);
    }

    @Override
    public Page<ProductSkuListVO> listSku(SkuQueryPageReqDTO in) {
        in.processingData();
        Page<ProductSkuListVO> result = this.baseMapper.queryPage(KingHoodPageUtil.getPage(in, in), in);
        result.getRecords().stream().forEach(i -> {
            if (!StringUtils.isEmpty(i.getHdPicture())) {
                i.setPicture(i.getHdPicture());
            } else if (!StringUtils.isEmpty(i.getOperationPicture())) {
                i.setPicture(i.getOperationPicture());
            } else if (!StringUtils.isEmpty(i.getHandPicture())) {
                i.setPicture(i.getHandPicture());
            } else if (!StringUtils.isEmpty(i.getFactoryPicture())) {
                i.setPicture(i.getFactoryPicture());
            }
            if (!StringUtils.isEmpty(i.getPicture())) {
                String[] split = i.getPicture().split(",");
                if (split.length > 0) {
                    i.setPicture(split[0]);
                }
            }
            i.setSkuStatusTxt(StatusEnum.getNameByStatus(i.getSkuStatus()));
        });

        Set<Long> userIdList = new HashSet<>();
        for (ProductSkuListVO record : result.getRecords()) {
            userIdList.add(record.getCreateUserId());
            userIdList.add(record.getUpdateUserId());
        }
        userIdList.remove(null);
        if (!CollectionUtils.isEmpty(userIdList)) {
            Map<Long, UserRemoteVo> userMap = userRemote.getUserByIds(new ArrayList<Long>(userIdList));
            for (ProductSkuListVO record : result.getRecords()) {
                record.setCreateUserName(UserNameUtil.getName(record.getCreateUserId(), userMap));
                record.setUpdateUserName(UserNameUtil.getName(record.getUpdateUserId(), userMap));
            }
        }
        return result;
    }

    @Override
    public ProductDTO getProductSku(GetProductSkuReqDTO in) {

        GetProductBaseDTO baseDTO = productBaseMapper.getBase(in.getProductId());
        KingHoodExceptionUtil.isNull(baseDTO,"商品不存在");
        ProductDTO res = new ProductDTO();
        BeanUtils.copyProperties(baseDTO, res);

        List<SkuDTO> skuInfoList = this.getBaseMapper().getProductSku(in);
        if(CollectionUtils.isEmpty(skuInfoList)){
            return res;
        }
        BaseProductDTODO product = ProductBaseHandler.changeToProductInfo(skuInfoList);
        product.setId(baseDTO.getProductId());
        product.setStyleName(baseDTO.getStyleName());
        product.setStyleNumber(baseDTO.getStyleNumber());
        product.setStatus(baseDTO.getStatus());
        product.setProductTemplateId(baseDTO.getProductTemplateId());
        product.handNull();
        BeanUtils.copyProperties(product, res);

        List<ProductAttributeDO> attributeList = productAttributeService.getByProductId(baseDTO.getProductId(),null);
        Map<String, List<ProductAttributeDO>> attributeMap = attributeList.stream()
                .collect(Collectors.groupingBy(k -> k.getBusinessId() + "-" + k.getBusinessType()));

        res.setProductBase(ProductBaseHandler.getProductBase(product, attributeMap));
        res.setSkuList(ProductBaseHandler.getSkuList(product, attributeMap));
        res.setSkuExtrasList(ProductBaseHandler.getSkuExtrasList(product, attributeMap));
        res.setSkuSupplierList(ProductBaseHandler.getSkuSupplierList(product, attributeMap));

        return res;
    }

    /**
     * 获取sku属性
     *
     * @param businessCode 业务代码
     * @return @return {@link Object }
     * @author jp
     * @date 2024/01/23 15:28
     */
    @Override
    public Object getSkuFields(String businessCode) {
        List<AttributeNameVO> result = new ArrayList<>();
        result.add(new AttributeNameVO("styleInfo", 0,"款式信息"));
        result.add(new AttributeNameVO("skuCode", 0,"SKU编码"));
        List<AttributeNameVO> attributeList = this.baseMapper.getSkuAttribute();
        attributeList.forEach(i -> i.setCodeType(1));
        result.addAll(attributeList);
        // 要求这几个字段放在最后展示
        result.add(new AttributeNameVO("skuStatusTxt", 0,"状态"));
        result.add(new AttributeNameVO("createUserName",0, "创建人"));
        result.add(new AttributeNameVO("createTime", 0,"创建时间"));
        result.add(new AttributeNameVO("updateTime",0, "最后修改时间"));
        result.add(new AttributeNameVO("updateUserName", 0,"最后操作人"));

        GetUserSearchSettingReqDTO settingReqDTO = new GetUserSearchSettingReqDTO();
        settingReqDTO.setBusinessType(2);
        settingReqDTO.setBusinessCode(businessCode);
        GetUserSearchSettingVO res = userSearchSettingService.getUserSearchSetting(settingReqDTO);
        if (Objects.nonNull(res) && !CollectionUtils.isEmpty(res.getShowList())) {
            Map<String, String> codeMap = res.getShowList().stream().collect(Collectors.toMap(SearchSettingVO::getCode, SearchSettingVO::getCode, (x, y) -> x));
            for (AttributeNameVO field : result) {
                String code = codeMap.get(field.getCode());
                if (!StringUtils.isEmpty(code)) {
                    field.setIsShow(true);
                }
            }
        } else {
            // 没有配置，给系统值设置默认值
            result.stream().filter(i -> i.getCodeType() == 0).forEach(i -> i.setIsShow(true));
        }
        return result;
    }

    /**
     * 获取sku搜索属性
     *
     * @param businessCode 业务代码
     * @return @return {@link Object }
     * @author jp
     * @date 2024/01/23 15:28
     */
    @Override
    public Object getSkuSearchFields(String businessCode) {
        List<AttributeNameVO> result = new ArrayList<>();
        result.add(new AttributeNameVO("styleName", 0,"款式名称"));
        result.add(new AttributeNameVO("styleNumber", 0,"款式编号"));
        result.add(new AttributeNameVO("brandList", 0,"品牌"));
        result.add(new AttributeNameVO("goodsList",0,"货类"));
        result.add(new AttributeNameVO("categoryList",0, "品类"));
        result.add(new AttributeNameVO("skuCode",0, "SKU编码"));
        result.add(new AttributeNameVO("createTime",0, "创建时间"));

        List<AttributeNameVO> attributeList = this.baseMapper.getSkuAttribute();
        AttributeCodesReqDTO attributeCodesReqDTO = new AttributeCodesReqDTO();
        attributeCodesReqDTO.setCodes(attributeList.stream().map(AttributeNameVO::getCode).collect(Collectors.toList()));
        // 查询属性数据
        List<AttributeReqDTO> attList = baseAttributeService.attributeByCodes(attributeCodesReqDTO);
        Map<String, AttributeReqDTO> attMap = attList.stream().collect(Collectors.toMap(AttributeReqDTO::getAttributeCode, i -> i, (x,y) -> x));
        attributeList.forEach(i -> {
            i.setCodeType(1);
            if (attMap.containsKey(i.getCode())) {
                i.setAttributeInfo(attMap.get(i.getCode()));
            }
        });
        result.addAll(attributeList);

        GetUserSearchSettingReqDTO settingReqDTO = new GetUserSearchSettingReqDTO();
        settingReqDTO.setBusinessType(1);
        settingReqDTO.setBusinessCode(businessCode);
        GetUserSearchSettingVO res = userSearchSettingService.getUserSearchSetting(settingReqDTO);
        if (Objects.nonNull(res) && !CollectionUtils.isEmpty(res.getSearchList())) {
            Map<String, String> codeMap = res.getSearchList().stream().collect(Collectors.toMap(SearchSettingVO::getCode, SearchSettingVO::getCode, (x, y) -> x));
            for (AttributeNameVO field : result) {
                String code = codeMap.get(field.getCode());
                if (!StringUtils.isEmpty(code)) {
                    field.setIsShow(true);
                }
            }
        } else {
            // 没有配置，给系统值设置默认值
            result.stream().filter(i -> i.getCodeType() == 0).forEach(i -> i.setIsShow(true));
        }

        return result;
    }

    /**
     * 数据入库
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveProductSkuDao(List<ProductExcelDaoDTO> productDaoList) {

        if (CollectionUtils.isEmpty(productDaoList)) {
            return;
        }
        List<ProductAttributeDO> attributes = new ArrayList<>();
        List<ProductSkuBaseDO> skuBaseList = new ArrayList<>();
        List<ProductSkuSupplierBaseDO> supplierBaseList = new ArrayList<>();
        List<ProductSkuExtrasBaseDO> extrasBaseList = new ArrayList<>();
        productDaoList.forEach(x -> {
            attributes.addAll(x.getAttributes());
            skuBaseList.addAll(x.getSkuBaseList());
            supplierBaseList.addAll(x.getSupplierBaseList());
            extrasBaseList.addAll(x.getExtrasBaseList());
        });

        if(!CollectionUtils.isEmpty(attributes)){
            productAttributeService.saveBatch(attributes);
        }
        if(!CollectionUtils.isEmpty(skuBaseList)){
            this.saveBatch(skuBaseList);
        }
        if(!CollectionUtils.isEmpty(supplierBaseList)){
            productSkuSupplierBaseService.saveBatch(supplierBaseList);
        }
        if(!CollectionUtils.isEmpty(extrasBaseList)){
            productSkuExtrasBaseService.saveBatch(extrasBaseList);
        }

        if(!CollectionUtils.isEmpty(skuBaseList)){
            ArrayList<BusinessLogDO> logs = new ArrayList<>();
            skuBaseList.forEach(x->{
                BusinessLogDO log = new BusinessLogDO();
                log.setId(IdGenUtil.getId());
                log.setProductId(x.getProductId());
                log.setSkuId(x.getId());
                log.setContent("导入SKU编码："+x.getSkuCode());
                log.setOperate(BusinessLogOperateEnum.UPLOAD_SKU.getType());
                log.setCreateTime(LocalDateTime.now());
                log.setCreateUserId(UserUtil.getUserId());
                logs.add(log);
            });
            asyncBusinessLogService.addLogBatch(logs);
        }
    }

    @Override
    public void updateSkuStatus(StatusRemarkReqDTO param) {
        List<ProductSkuBaseDO> skuBaseDOS = this.lambdaQuery()
                .eq(ProductSkuBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .in(ProductSkuBaseDO::getId, param.getIdList())
                .list();
        this.lambdaUpdate().set(ProductSkuBaseDO::getSkuStatus, param.getStatus())
                .set(ProductSkuBaseDO::getUpdateUserId, UserUtil.getUserId())
                .set(ProductSkuBaseDO::getUpdateTime, LocalDateTime.now())
                .eq(ProductSkuBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .in(ProductSkuBaseDO::getId, param.getIdList())
                .update();
        // 加入日志
        if(!CollectionUtils.isEmpty(skuBaseDOS)){
            ArrayList<BusinessLogDO> logs = new ArrayList<>();
            skuBaseDOS.forEach(x->{
                String conent = String.format("状态：从[%s]变更为[%s]", StatusEnum.getNameByStatus(x.getSkuStatus()),
                        ProductStatusEnums.getNameByType(param.getStatus()));
                if (!StringUtils.isEmpty(param.getRemark())) {
                    conent = conent + "；备注：" + param.getRemark();
                }
                BusinessLogDO log = new BusinessLogDO();
                log.setId(IdGenUtil.getId());
                log.setProductId(x.getProductId());
                log.setSkuId(x.getId());
                log.setContent(conent);
                log.setOperate(BusinessLogOperateEnum.UPDATE_STATUS.getType());
                log.setCreateTime(LocalDateTime.now());
                log.setCreateUserId(UserUtil.getUserId());
                logs.add(log);
            });
            asyncBusinessLogService.addLogBatch(logs);
        }
    }

    @Override
    public void delSku(Long id) {
        this.lambdaUpdate().set(ProductSkuBaseDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(ProductSkuBaseDO::getUpdateTime, LocalDateTime.now())
                .set(ProductSkuBaseDO::getUpdateUserId, UserUtil.getUserId())
                .eq(ProductSkuBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(ProductSkuBaseDO::getId, id)
                .update();
    }
}
